//! Copyright 2012 Xicut Technology, Inc.
//! All rights reserved
//!
#include "StrLib.h"
#include "BoardHardware.h"
#include "UsartDriver.h"

#if defined (__FW_BUILD__)
extern "C"  {
#include "stm32f10x.h"
#include "stm32f10x_usart.h"

    U8 s_pTxBuffer[TX_BUFF_LEN];
    volatile U8 s_TxSendingFlag;
    #if TX_BUFF_LEN < 255
        volatile U8 s_TxLen;
        volatile U8 s_TxCount;
    #else
        volatile U16 s_TxLen;
        volatile U16 s_TxCount;
    #endif

    U8 s_pRxFIFOBuff[RX_FIFO_BUFF_LEN];
    volatile U8 s_RxCount;
    volatile U8 s_RxHead;
    volatile U8 s_RxTail;

    void SIM900_USART_IRQHandler(void)
    {
        U8 data;

        if(USART_GetITStatus(SIM900_USART, USART_IT_RXNE) != RESET)
        {
            /* Read one byte from the receive data register */
            data = USART_ReceiveData(SIM900_USART);
            if ( RX_FIFO_BUFF_LEN != s_RxCount )
            {
                s_pRxFIFOBuff[ s_RxTail++ ] = data;
                if (RX_FIFO_BUFF_LEN == s_RxTail) { s_RxTail = 0; }
                ++s_RxCount;
            }
        }

        if(USART_GetITStatus(SIM900_USART, USART_IT_TXE) != RESET)
        {   
            /* Write one byte to the transmit data register */
            if (s_TxLen >= s_TxCount)
            {
                USART_SendData(SIM900_USART, s_pTxBuffer[s_TxCount++]);
                s_TxSendingFlag = _TRUE_;
            }
            else
            {
                USART_ITConfig(SIM900_USART, USART_IT_TXE, DISABLE);
                s_TxSendingFlag = _FALSE_;
            } 
        }
    }
};  // extern "C"
#else
    U8 cUsartDriver::s_pTxBuffer[TX_BUFF_LEN];
    volatile U32 cUsartDriver::s_TxSendingFlag;
    volatile U32 cUsartDriver::s_TxLen;
    volatile U32 cUsartDriver::s_TxCount;

    U8 cUsartDriver::s_pRxFIFOBuff[RX_FIFO_BUFF_LEN];
    volatile U32 cUsartDriver::s_RxCount;
    volatile U32 cUsartDriver::s_RxHead;
    volatile U32 cUsartDriver::s_RxTail;
#endif

U8 cUsartDriver::s_pRxBuff[RX_BUFF_LEN];
U16 cUsartDriver::s_RxBuffCount;
U8 cUsartDriver::s_pRxTempBuff[RX_BUFF_LEN];
U16 cUsartDriver::s_RxTempBuffCount;


void cUsartDriver::Init_Reset(U16 iBaudRate)
{
    #if defined (__FW_BUILD__)
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    /* Enable GPIO clock */
    RCC_APB2PeriphClockCmd(TX_RX_PERIPH, ENABLE);
    /* Enable SIM900_USART Clock */
    RCC_APB1PeriphClockCmd(SIM900_USART_PERIPH, ENABLE); 

    /* Configure the NVIC Preemption Priority Bits */  
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    /* Enable the USARTy Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = SIM900_USART_ISR;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    /* Configure USART Rx as input floating */
    GPIO_InitStructure.GPIO_Pin = RX_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(TX_RX_PORT, &GPIO_InitStructure);
    /* Configure USART Tx as alternate function push-pull */
    GPIO_InitStructure.GPIO_Pin = TX_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(TX_RX_PORT, &GPIO_InitStructure);

    /* Configure SIM900_USART */
    USART_InitStructure.USART_BaudRate = iBaudRate;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(SIM900_USART, &USART_InitStructure);

    /* Enable USARTy Receive and Transmit interrupts */
    USART_ITConfig(SIM900_USART, USART_IT_RXNE, ENABLE);
    USART_ITConfig(SIM900_USART, USART_IT_TXE, DISABLE);

    /* Enable the SIM900_USART */
    USART_Cmd(SIM900_USART, ENABLE);
    #endif

    s_TxSendingFlag = _FALSE_;
    s_TxLen = 1;
    s_TxCount = 0;

    s_RxCount = 0;
    s_RxHead = 0;
    s_RxTail = 0;

    s_RxBuffCount = 0;
    s_RxTempBuffCount = 0;
}


U8* cUsartDriver::GetIncomeMsg(U16 &iLen)
{
    if (0 == s_RxBuffCount)
    {
        iLen = 0;
        return (0);
    }
    else
    {
        iLen = s_RxBuffCount;
        s_RxBuffCount = 0;
        return (s_pRxBuff);
    }
}


bool cUsartDriver::SendMsg(U8 *pOutData, U16 count)
{
    while (_TRUE_ == s_TxSendingFlag);
    cStrLib::Strcpy(s_pTxBuffer, pOutData, count);
    s_TxCount = 1;
    s_TxLen = count;
    s_TxSendingFlag = _TRUE_;
#if defined (__FW_BUILD__)
    USART_SendData(SIM900_USART, s_pTxBuffer[0]);
    USART_ITConfig(SIM900_USART, USART_IT_TXE, ENABLE);
#endif
    return (true);
}


void cUsartDriver::RunOne()
{
    while (0 != s_RxCount)
    {
        // pop data from RxFIFOBuffer
        U8 tempData = s_pRxFIFOBuff[s_RxHead];
        ++s_RxHead;
        if (RX_FIFO_BUFF_LEN == s_RxHead) {s_RxHead = 0;}
        --s_RxCount;

        // move data incoming to RxTempBuff
        s_pRxTempBuff[s_RxTempBuffCount] = tempData;
        ++s_RxTempBuffCount;

        // check STX in data coming
        if ('\n' == tempData)
        {
            if ((2 < s_RxTempBuffCount) && ('\r' == s_pRxTempBuff[s_RxTempBuffCount-2]))
            {
                cStrLib::Strcpy(s_pRxBuff, s_pRxTempBuff, s_RxTempBuffCount);
                s_RxBuffCount = s_RxTempBuffCount;
                s_RxTempBuffCount = 0;
            }
        }
        else if (' ' == tempData)
        {
            if ((2 <= s_RxTempBuffCount) && ('>' == s_pRxTempBuff[s_RxTempBuffCount-2]))
            {
                s_pRxBuff[0] = '>';
                s_pRxBuff[1] = ' ';
                s_RxBuffCount = 2;
                s_RxTempBuffCount = 0;
            }
        }
    }
}

